package com.michaelbulava.TFS.ui.controls.connect;

import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.application.ModalityState;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.michaelbulava.TFS.common.catalog.TeamProjectCollectionInfo;
import com.microsoft.tfs.core.TFSConfigurationServer;
import com.microsoft.tfs.core.TFSConnection;
import com.microsoft.tfs.core.TFSTeamProjectCollection;
import com.microsoft.tfs.core.clients.framework.configuration.entities.ProjectCollectionEntity;
import com.microsoft.tfs.core.clients.framework.configuration.entities.TeamFoundationServerEntity;
import com.microsoft.tfs.util.GUID;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import java.awt.*;
import java.net.URL;
import java.text.MessageFormat;

/**
 * Created by mbulava on 6/15/2015.
 */
public class ProjectCollectionTable extends JTable {
    private ProjectCollectionTableModel tableModel;

    public ProjectCollectionTable(){
        super();
        tableModel = new ProjectCollectionTableModel();
        setModel(tableModel);
        setDefaultRenderer(String.class, new ProjectCollectionTableRenderer());
        getColumnModel().getColumn(0).setCellRenderer(new ProjectCollectionTableRenderer());
        setCellSelectionEnabled(true);
        ListSelectionModel cellSelectionModel = getSelectionModel();
        cellSelectionModel.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        this.setTableHeader(null);
    }

    public void setTFSConnection(TFSConnection connection){
        tableModel.refresh(connection);
    }

    public TeamProjectCollectionInfo getSelectedCollection(){
        int selectedRow = getSelectedRow();
        if (selectedRow == -1)
            return null;
        return tableModel.elements[selectedRow];
    }

    public void setSelectedProjectCollection(GUID projectCollectionId) {
        if (projectCollectionId == null)
            return;

        getSelectionModel().clearSelection();
        for(int i = 0; i < tableModel.elements.length; i++){
            TeamProjectCollectionInfo info = tableModel.elements[i];
            if (info.getIdentifier().equals(projectCollectionId)) {
                //addRowSelectionInterval(i, i);
                //getSelectionModel().addSelectionInterval(i,i);
                //super.setRowSelectionInterval(i,i);
                super.changeSelection(i, 0, true, false);

                return;
            }
        }
    }

    private class ProjectCollectionTableRenderer extends DefaultTableCellRenderer {
        @Override
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
                                                       boolean hasFocus, int row, int column) {
            JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
            URL image = getClass().getResource("/images/common/team_foundation_server.gif");
            ImageIcon icon = new ImageIcon(image);
            l.setText((String)value);
            l.setIcon(icon);

            String description = tableModel.elements[row].getDescription();
            if (description != null && description.length() > 0)
                l.setToolTipText(description);
            else
                l.setToolTipText("");

            return l;
        }
    }

    private class ProjectCollectionTableModel extends AbstractTableModel {
        private TeamProjectCollectionInfo[] elements;
        private final Object lock = new Object();

        /**
         * Returns the number of rows in the model. A <code>JTable</code> uses this method to determine how many rows it
         * should display.  This method should be quick, as it is called frequently during rendering.
         *
         * @return the number of rows in the model
         * @see #getColumnCount
         */
        @Override
        public int getRowCount() {
            synchronized (lock){
                return elements == null ? 0 : elements.length;
            }
        }

        /**
         * Returns the number of columns in the model. A <code>JTable</code> uses this method to determine how many columns
         * it should create and display by default.
         *
         * @return the number of columns in the model
         * @see #getRowCount
         */
        @Override
        public int getColumnCount() {
            return 1;
        }

        /**
         * Returns the value for the cell at <code>columnIndex</code> and <code>rowIndex</code>.
         *
         * @param    rowIndex    the row whose value is to be queried
         * @param    columnIndex the column whose value is to be queried
         * @return the value Object at the specified cell
         */
        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            if (columnIndex == 0)
                return elements[rowIndex].getDisplayName();
            return "";
        }

        @Override
        public Class getColumnClass(int c) {
            return String.class;
        }

        private void setData(TeamProjectCollectionInfo[] items){
            synchronized (lock){
                elements = items;

                ApplicationManager.getApplication().invokeAndWait(new Runnable() {

                    @Override
                    public void run() {
                        fireTableDataChanged();
                    }
                }, ModalityState.stateForComponent(ProjectCollectionTable.this));
            }
        }

        public void refresh(TFSConnection connection){
            if (connection == null)
                setData(null);

            if (connection instanceof TFSTeamProjectCollection){
                //Legacy collection
                TeamProjectCollectionInfo[] legacyCollection = { new TeamProjectCollectionInfo(GUID.EMPTY,
                        MessageFormat.format("({0})", //Messages.getString("TeamProjectSelectControl.DisplayUrlFormat"),
                                new Object[]{connection.getName()}),
                        MessageFormat.format("Team Foundation Server instance for {0}",//Messages.getString("TeamProjectSelectControl.TfsInstanceFormat")
                                new Object[] { connection.getBaseURI() })) };
                setData(legacyCollection);
            } else if (connection instanceof TFSConfigurationServer){
                setConfigurationServer((TFSConfigurationServer) connection);
            }
        }

        private void setConfigurationServer(TFSConfigurationServer configurationServer){
            ProjectCollectionTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
            QueryProjectCollectionsTask task = new QueryProjectCollectionsTask(configurationServer);
            ProgressManager.getInstance().run(task);
            setData(task.getProjectCollections());
            ProjectCollectionTable.this.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
        }
    }

    private class QueryProjectCollectionsTask extends Task.Modal{
        private final TFSConfigurationServer connection;
        private TeamProjectCollectionInfo[] collections;

        public QueryProjectCollectionsTask(TFSConfigurationServer connection) {
            super(null, "Querying project collections", true);
            this.connection = connection;
        }

        @Override
        public void run(@NotNull ProgressIndicator indicator) {
            indicator.setText("Querying project collections");
            indicator.setIndeterminate(true);
            try{
                TeamFoundationServerEntity teamFoundationServerEntity = connection.getTeamFoundationServerEntity(true);
                if (teamFoundationServerEntity != null){
                    ProjectCollectionEntity[] projectCollectionEntities = teamFoundationServerEntity.getProjectCollections();
                    if (projectCollectionEntities != null){
                        this.collections = new TeamProjectCollectionInfo[projectCollectionEntities.length];
                        for(int i = 0; i < projectCollectionEntities.length; i++){
                            this.collections[i] = new TeamProjectCollectionInfo(projectCollectionEntities[i].getInstanceID(),
                                    projectCollectionEntities[i].getDisplayName(), projectCollectionEntities[i].getDescription());
                        }
                    }
                }
            } finally {
                indicator.stop();
            }
        }

        public TeamProjectCollectionInfo[] getProjectCollections(){
            return this.collections;
        }
    }



}



